Lattice is very capable and improves on traditional base graphics. The design goals were:
The main elements are:
Additional arguments to the high-level functions are used to activate common variants, and full flexibility is allowed through arbitrary user-defined functions (e.g. controlling the primary display through panel functions)
Each density plot is in an area called a panel. Panel sizes determined automatically. Axes annotated with tick marks and labels only along boundaries saving space. Strips atop each panel display info
A formula describes the content of the plots.
The first argument to many lattice functions is a formula argument describing variables to plot. A trellis formula looks like
The ~ is what makes it a formula. The vertical bar denotes denotes conditioning and may be omitted.
So a and b are conditioning variables and the y and x are called the primary variables. At least one primary variable must be specified. (Unlike modelling functions, * and + in conditioning variables are treated identically in lattice. Thus, these are valid trellis functions in lattice.)
The formula can include method calls like sqrt() or log() to transform individual variables.
Some examples.
| Formula | Lattice Plot |
|---|---|
z ~ x * y |
Three dimensional plot |
y1 + y2 ~ x |
Plot two \(y\)’s versus \(x\) |
y ~ x1 + x2 |
Plot \(y\) versus two \(x\)s |
y ~ x| g1 + g2 + ... |
Plot \(y\) versus \(x\) conditioned on \(g\)s |
y ~ x| g1 * g2 * ... |
Plot \(y\) versus \(x\) conditioned on \(g\)s |
Mostly, the \(g\)’s are factors or shingles.
Shingles are a generalization of factors for continuous variables. They are a way of discretizing continuous values (using cut, for example), except that the intervals may overlap. So an observation may be assigned to more than one interval.
The formula y ~ x | g indicates that several plots should be generated, showing \(y\) against \(x\) for each level of \(g\).
Each unique combination of the levels of the conditioning variables determines a packet, a subset of the primary variables for that combination.
| Lattice Func. | Lattice Description | Base Analog |
|---|---|---|
barchart |
Barcharts | barplot |
bwplot |
Boxplots | boxplot |
densityplot |
Conditional kernel density plots | |
dotplot |
Dotplots | dotchart |
histogram |
Histograms | hist |
qqmath |
Quantile–quantile plots | qqnorm |
stripplot |
Strip plots | stripchart |
qq |
Quantile–quantile plots | qqplot |
xyplot |
Scatterplots | plot |
levelplot |
Level plots | image |
contourplot |
Contour plots | contour |
cloud |
3-dimensional scatterplot | |
wireframe |
3-dimensional surfaces | persp |
splom |
Scatterplot matrices | pairs |
parallel |
Parallel coordinate plots |
Various types of plots can be obtained by means of plot type specifications (argument type).
| Type | Effect | Panel function |
|---|---|---|
"p" |
Plot points | |
"l" |
Join points by line | |
"b" |
Both lines and points | |
"o" |
Points and lines overlaid | |
"S" "s" |
Plot as step function | |
"h" |
Drop lines to origin | |
"a" |
Join lines after averaging | panel.average |
"r" |
Join regression line | panel.lmline |
"smooth" |
Plot LOESS smooth | panel.loess |
"g" |
Plot a reference grid | panel.grid |
Extra info can be added to a plot by specifying a panel function via the panel arguments.
For example, the default panel function for an xyplot is panel.xyplot().
This draws the default contents for a panel, so you want to call this as part of a custom panel function"
The arguments differ from function to function (see docs). Common ones: x, y and z and subscripts (indices to subset for each panel).
Function hooks, such as a prepanel function hook to control the size and scaling of panels (maybe make space for some text you want to show) and a strip function for controlling what gets drawn in the strips of a lattice plot.
Creating a separate panel for each plot
Plot all three species in a single panel.
Plot without the points.
densityplot(~Sepal.Length + Sepal.Width +
Petal.Length + Petal.Width, group=Species,
data=iris, plot.points=FALSE, ref=TRUE)Add in a legend
densityplot(~Sepal.Length + Sepal.Width + Petal.Length +
Petal.Width, group=Species, data=iris,
ref=TRUE, plot.points=FALSE,
auto.key=list(columns=3))Some formula details: * and + are treated similarly only in the conditioning part of the formula!
densityplot(~Sepal.Length * Sepal.Width * Petal.Length *
Petal.Width, group=Species, data=iris,
ref=TRUE, plot.points=FALSE,
auto.key=list(columns=3))An example normal quantile plot:
qqdata <- data.frame(x = c(rnorm(100), qnorm(ppoints(100))),
y = c(rep("x", 100),
rep("Normal Quantile", 100)))
qq(y ~ x, data=qqdata, col="red", lwd=3) ___
See for example ?barley. This is a data set containing total yield in bushels per acre for 10 varieties at 6 sites in each of two years.
## 'data.frame': 120 obs. of 4 variables:
## $ yield : num 27 48.9 27.4 39.9 33 ...
## $ variety: Factor w/ 10 levels "Svansota","No. 462",..: 3 3 3 3 3 3 7 7 7 7 ...
## $ year : Factor w/ 2 levels "1932","1931": 2 2 2 2 2 2 2 2 2 2 ...
## $ site : Factor w/ 6 levels "Grand Rapids",..: 3 6 4 5 1 2 3 6 4 5 ...
We can examine some boxplots.
Some dot plots.
We add groups distinguished by color
Condition on site.
Group by year and then condition on site.
We need to add color to see difference.
Note that conditioning on both makes things less obvious.
So go back to condition on site and group by year and add a legend
dotplot(variety ~ yield | site, data = barley, groups = year,
col=c("red", "blue"),
auto.key=list(columns=2, col=c("red", "blue")))The plot symbol color is screwed up in the previous dotplot. So we better have a separate symbol for each.
dotplot(variety ~ yield | site, data = barley, groups = year,
pch=c(2, 4),
col=c("red", "blue"),
auto.key=list(columns=2, col=c("red", "blue")))Hmmm. Plot symbol still screwed up, so build legend manually
dotplot(variety ~ yield | site, data = barley, groups = year,
col=c("red", "blue"),
pch=c(2, 4),
key=list(text=list(c("1932", "1931")),
columns=2,
col=c("red", "blue")))We can save plots to various formats such as pdf, png etc.
pdf(file="yield.pdf", paper="letter", width=8, height=10.5)
dotplot(variety ~ yield | site, data = barley, groups = year,
col=c("red", "blue"),
pch=c(2, 4),
key=list(text=list(c("1932", "1931")),
columns=2,
col=c("red", "blue")))
dev.off()## quartz_off_screen
## 2
One nice thing about lattice (and ggplot) is that the plots are actually objects. They don’t plot until you print them.
## Incremental updating
tp1 <- densityplot(~Sepal.Length+Sepal.Width+
Petal.Length+Petal.Width,group=Species,data=iris)
print(tp1)You can also update the object (will not affect tp1 above.)
Add the legend.
You can examine tp3 like any other object.
## [1] "formula" "as.table" "aspect.fill"
## [4] "legend" "panel" "page"
## [7] "layout" "skip" "strip"
## [10] "strip.left" "xscale.components" "yscale.components"
## [13] "axis" "xlab" "ylab"
## [16] "xlab.default" "ylab.default" "xlab.top"
## [19] "ylab.right" "main" "sub"
## [22] "x.between" "y.between" "par.settings"
## [25] "plot.args" "lattice.options" "par.strip.text"
## [28] "index.cond" "perm.cond" "condlevels"
## [31] "call" "x.scales" "y.scales"
## [34] "panel.args.common" "panel.args" "packet.sizes"
## [37] "x.limits" "y.limits" "x.used.at"
## [40] "y.used.at" "x.num.limit" "y.num.limit"
## [43] "aspect.ratio" "prepanel.default" "prepanel"
## $top
## $top$fun
## [1] "drawSimpleKey"
##
## $top$args
## $top$args$text
## [1] "setosa" "versicolor" "virginica"
##
## $top$args$columns
## [1] 3
And even pick off one of the plots.
___
tp = xyplot(lat~long, data=quakes, pch=".")
update(tp,
main="Earthquakes in the Pacific Ocean\n(since 1964)")We can apply a 3-level shingle, no overlap.
depthgroup <- equal.count(quakes$depth, number=3,
overlap=0)
magnitude <- equal.count(quakes$mag, number=2,
overlap=0)
xyplot(lat ~ long | depthgroup*magnitude,
data=quakes,main="Fiji Earthquakes",
ylab="latitude", xlab="longitude",
pch=".",
scales=list(x=list(alternating=c(1,1,1))),
between=list(y=1),
par.strip.text=list(cex=0.7),
par.settings=list(axis.text=list(cex=0.7)))Trellis graphics in Splus to produce a whole series of plots.## R version 3.6.2 (2019-12-12)
## Platform: x86_64-apple-darwin19.2.0 (64-bit)
## Running under: macOS Catalina 10.15.2
##
## Matrix products: default
## BLAS/LAPACK: /usr/local/Cellar/openblas/0.3.7/lib/libopenblasp-r0.3.7.dylib
##
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
##
## attached base packages:
## [1] stats graphics grDevices datasets utils methods base
##
## other attached packages:
## [1] lattice_0.20-38 rmarkdown_2.0 knitr_1.26 pkgdown_1.4.1
## [5] devtools_2.2.1 usethis_1.5.1
##
## loaded via a namespace (and not attached):
## [1] Rcpp_1.0.3 magrittr_1.5 MASS_7.3-51.5 pkgload_1.0.2
## [5] R6_2.4.1 rlang_0.4.3 fansi_0.4.1 stringr_1.4.0
## [9] tools_3.6.2 grid_3.6.2 pkgbuild_1.0.6 xfun_0.11
## [13] sessioninfo_1.1.1 cli_2.0.1 withr_2.1.2 htmltools_0.4.0
## [17] ellipsis_0.3.0 remotes_2.1.0 yaml_2.2.0 assertthat_0.2.1
## [21] digest_0.6.23 rprojroot_1.3-2 crayon_1.3.4 processx_3.4.1
## [25] callr_3.4.0 fs_1.3.1 ps_1.3.0 testthat_2.3.1
## [29] evaluate_0.14 memoise_1.1.0 glue_1.3.1 stringi_1.4.5
## [33] compiler_3.6.2 desc_1.2.0 backports_1.1.5 prettyunits_1.1.0